package bitmap;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.StringTokenizer;
import java.util.Vector;

import colour.Colour;
import bitmap.IPPM;

/**
 * This is a class which realizes the operation of writing and reading groups of
 * colour components in ASCII which is identified by P3
 * 
 * @author Yuting Wu
 * @author Kan Lin
 * @author Bing Dong
 * 
 * @param width
 *            the width of the image
 * @param height
 *            the height of the image
 * @param maxColourValue
 *            maximal value can be handled
 * @param pixels
 *            array for the rgb value
 * 
 */

public class BitmapInP3 implements IPPM {

	private Bitmap bpWrite;
	private int width;
	private int height;
	private int maxColourValue;
	
	

	public BitmapInP3(int width, int height,
			int maxColourValue){
		this.width = width;
		this.height = height;
		this.maxColourValue = maxColourValue;
		
	}
	// Constructors
	public BitmapInP3(Bitmap bpWrite) {
		
		this.bpWrite = bpWrite;
		this.maxColourValue = bpWrite.getMaxColourValue();

	}

	

	/**
	 * This is a method used for reading the colour segemnt
	 * 
	 * @param fis
	 * @param firstByte
	 * @return a array stores all of the colour component
	 */
	public Colour[][]  readColour(FileInputStream fis, int firstByte) {
		Colour[][] pixels = new Colour[height][width];
		BufferedReader in = new BufferedReader(new InputStreamReader(fis));
		Vector<String> tempColour = new Vector<String>(1);

		int red = -1;
		int green = -1;
		int blue = -1;
		int i = 3; // R G B

		int number = 0;

		int nHeight = 0;
		int nWidth = 0;
		
		try {
			red = firstByte;
			String temp;

			while ((temp = in.readLine()) != null) {
				// call the method to deal with the msg in a line
				tempColour = getMessageFromLine(temp);

				for (int j = 0; j < tempColour.size(); j++) {

					if (i == 3) {
						red = Integer.parseInt(tempColour.get(j).toString());
						i--;
					} else if (i == 2) {
						green = Integer.parseInt(tempColour.get(j).toString());
						i--;
					} else if (i == 1) {
						blue = Integer.parseInt(tempColour.get(j).toString());
						i--;
					}

					if (i == 0) {
						// To check whether the dara of color component is right
						// or wrong
						if (valueCheck(red, green, blue)) {
							pixels[nHeight][nWidth] = new Colour(red,
									green, blue);
							number++;
						} else {
							System.out
									.println("The data of color component is wrong!");
							return null;
						}
						nWidth++;
						if (nWidth == this.width) {
							nHeight++;
							nWidth = 0;
						}
						if (number > this.height * this.width) {
							System.out
									.println("The number of color component is wrong!");
							return null;
						}

						i = 3;
					}
				}
			}

		} catch (Exception e) {
			System.out.println("some errors in the reading colours in P3");
			return null;
		}

		return pixels;
	}

	/**
	 * This is a method for checking whether the value is correct
	 * 
	 * @param red
	 * @param green
	 * @param blue
	 * @return
	 */
	private boolean valueCheck(int red, int green, int blue) {
		return (red <= maxColourValue && red >= 0
				&& green <= maxColourValue && green >= 0
				&& blue <= maxColourValue && blue >= 0);

	}

	/**
	 * This is a method of Reading message each line in ASCII divided by the whitespace and put them
	 * into a Vector.
	 * 
	 * 
	 * @param line
	 *            a string of line which are given by the outside
	 * 
	 * @return a Vector stores the message which are divided
	 * 
	 * @see Vector
	 * 
	 */

	private Vector<String> getMessageFromLine(String line) {
		Vector<String> vecMsg = new Vector<String>(1);
		try {

			// String line = in.readLine();
			StringTokenizer st = new StringTokenizer(line);
			while (st.hasMoreTokens()) {
				String num = st.nextToken();
				if (num != null && num != "#") {
					vecMsg.add(num);
				} else {
					break;
				}
			}
		} catch (Exception e) {
			System.out.println("read width and height error");
		}
		return vecMsg;
	}

	/**
	 * Writing each colour component as a decimal number in ASCII with
	 * whitespace between the components. No single line reach more than 70
	 * characters It implements the interface IPPM.
	 * 
	 * 
	 * @param fos
	 *            the printstream for writing file
	 * @param whitespace
	 *            to divide between the colour component. In P6,it is useless.
	 * 
	 * @return a type of boolean shows whether it is successful for writing
	 * 
	 */
	public boolean writeColour(FileOutputStream fos, String whitespace) {
		// Transform the FileOutputStream into PrintStream
		
		PrintStream ps = new PrintStream(fos);

		int i = 0;
		int j = 0;

		// to record the number of colour components
		// which are written in one row
		int maxRow = 0;
		Colour colourValue;
		// check whether the array is empty, the size is right for height*width

		if (bpWrite.checkNumEuqal()) {

			for (i = 0; i < this.bpWrite.getHeight(); i++) {
				for (j = 0; j < this.bpWrite.getWidth(); j++) {

					// locate the position of the colour
					colourValue = bpWrite.getColourIndex(i,j);

					// to make sure that characters in each line reach less than
					// 70
					maxRow++;
					int[] rgb;
					rgb = colourValue.getRGB();

					if (maxRow < 5) {
						// print the colour component ends with blankspace
						ps.print(rgb[0] + whitespace + rgb[1] + whitespace
								+ rgb[2] + whitespace);
					} else {
						// print the colour component ends with CR+LF
						ps.println(rgb[0] + whitespace + rgb[1] + whitespace
								+ rgb[2]);
						maxRow = 0;
					}
				}
			}

		} else {
			System.out.println("The number of the data is wrong!");
			return false;
		}
		return true;
	}

}
